package ejb.contentManagement;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import ejb.dto.HotelAvailabilityDTO;
import entities.Hotel;
import entities.HotelAvailability;
import entities.Room;

@Stateless
public class HotelAvailabilityBean implements HotelAvailabilityMgr {
	
	@PersistenceContext
    private EntityManager em;
	
	/**
	 * Retrieve entity HotelAvailability from the associated Id
	 * @param id
	 * @return entity HotelAvailability associated to the <code>id</code>
	 */
	public HotelAvailability getHotelAvailability(int id) {
		return em.find(HotelAvailability.class, id);
	}
	
	/**
	 * Retrieve all HotelAvailability entities
	 * @return all HotelAvailability entities
	 */
	public List<HotelAvailability> getAllHotelAvailabilities() {
    	return em.createNamedQuery("HotelAvailability.findAll", HotelAvailability.class)
                .getResultList();
    }
	
	/**
	 * Retrieve entity HotelAvailability from the associated Id and convert it 
	 * to corresponding HotelAvailabilityDTO
	 */
	@Override
	public HotelAvailabilityDTO getHotelAvailabilityDTO(int id) {
		return  convertToDTO(getHotelAvailability(id));
    }
	
	/**
	 * Retrieve all HotelAvailability entities and convert them into 
	 * corresponding list of HotelAvailabilityDTO
	 */
	@Override
	public List<HotelAvailabilityDTO> getAllHotelAvailabilitiesDTO() {
		List<HotelAvailability> list = getAllHotelAvailabilities();
		List<HotelAvailabilityDTO> newList = new ArrayList<HotelAvailabilityDTO>();
		for(HotelAvailability obj : list) {
			newList.add(convertToDTO(obj));
		}
		return newList;
	}
	
	/**
	 * Retrieve all HotelAvailability entities associated to one hotel, and
	 * convert them into corresponding list of HotelAvailabilityDTO
	 */
	@Override
	public List<HotelAvailabilityDTO> getAllHotelAvailabilitiesDTO(int hotelId){
		Hotel hotel = em.find(Hotel.class, hotelId);
		List<HotelAvailability> list = em.createNamedQuery("HotelAvailability.findByHotel", HotelAvailability.class).setParameter("hot", hotel).getResultList();
		List<HotelAvailabilityDTO> newList = new ArrayList<HotelAvailabilityDTO>();
		for(HotelAvailability obj : list) {
			newList.add(convertToDTO(obj));
		}
		return newList;
	}
	
	/**
	 * Convert entity HotelAvailability (parameter <code>h</code>) into corresponding HotelAvailabilityDTO 
	 * @param h
	 * @return converted HotelAvailabilityDTO
	 */
	public static HotelAvailabilityDTO convertToDTO(HotelAvailability h) {
		if(h == null){
			return null;
		}
		HotelAvailabilityDTO dto = new HotelAvailabilityDTO();

		dto.setId(h.getId());
		dto.setFromDate(h.getFromDate());
		dto.setToDate(h.getToDate());
		dto.setPrice(h.getPrice());
		dto.setRemaining(h.getRemaining());
		dto.setHotelName(h.getHotel().getName());
		dto.setRoom(RoomBean.convertToDTO(h.getRoom()));
		return dto;
	}
	
	/**
	 * Retrieve entity HotelAvailability from the associated Id and delete 
	 * the corresponding element from the database
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public boolean deleteHotelAvailability(int id) {
		try{
			em.remove(em.find(HotelAvailability.class, id));
			em.flush();
		}
		//Catch exceptions in the delete operation from database
		catch(Exception e){
			return false;
		}
		return true;
	}
	
	/**
	 * Create entity HotelAvailability from corresponding HotelAvailabilityDTO 
	 * and update corresponding element in database
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public boolean updateHotelAvailability(HotelAvailabilityDTO updatedHotelAvailability) {
		if(updatedHotelAvailability.getRoom() == null ||
			updatedHotelAvailability.getFromDate() == null ||
			updatedHotelAvailability.getToDate() == null ||
			updatedHotelAvailability.getFromDate().compareTo(updatedHotelAvailability.getToDate()) > 0 ||
			updatedHotelAvailability.getPrice() < 0 ||
			updatedHotelAvailability.getPrice() > 50000 ||
			updatedHotelAvailability.getRemaining() < 0 ||
			updatedHotelAvailability.getRemaining() > 20000)
			return false;
		try{
			em.merge(new HotelAvailability(updatedHotelAvailability, em.find(Hotel.class, updatedHotelAvailability.getHotelId()), em.find(Room.class, updatedHotelAvailability.getRoomId())));
			em.flush();
		}
		//Catch exceptions in the update operation of database
		catch(Exception e){
			return false;
		}
		return true;
	}
	
	/**
	 * Create entity HotelAvailability from corresponding HotelAvailabilityDTO 
	 * and insert new corresponding element in database
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public boolean insertHotelAvailability(HotelAvailabilityDTO newHotelAvailability) {
		if(newHotelAvailability.getRoom() == null ||
			newHotelAvailability.getFromDate() == null ||
			newHotelAvailability.getToDate() == null ||
			newHotelAvailability.getFromDate().compareTo(newHotelAvailability.getToDate()) > 0 || 
			newHotelAvailability.getPrice() < 0 ||
			newHotelAvailability.getPrice() > 50000 ||
			newHotelAvailability.getRemaining() < 0 ||
			newHotelAvailability.getRemaining() > 20000)
			return false;
		try{
			em.persist(new HotelAvailability(newHotelAvailability, em.find(Hotel.class, newHotelAvailability.getHotelId()), em.find(Room.class, newHotelAvailability.getRoomId())));
			em.flush();
		}
		//Catch exceptions in the insert operation in database
		catch(Exception e){
			return false;
		}
		return true;
	}
	
	
}
